package cn.lbd;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricDetailQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.*;
import java.util.List;
import java.util.zip.ZipInputStream;

public class ActivitiDemo {

    /**
     * 部署流程定义
     */
    @Test
    public void testDeployment() {
        //1. 创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2. 得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3. 部署
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("bpmn/evection.bpmn")
                .name("出差申请流程")
                .deploy();
        //4. 打印部署信息
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

    /**
     * 启动流程实例
     */
    @Test
    public void testStartProcess() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //根据流程定义ID启动流程（act_re_procdef => KEY）
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvection");
        System.out.println("流程定义ID：" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例ID：" + processInstance.getId());
        System.out.println("当前活动ID：" + processInstance.getActivityId());
    }

    /**
     * 查看当前个人待执行任务
     */
    @Test
    public void testFindPersonalTaskList() {
        //负责人应该通过当前登录用户，即整合SpringSecurity查出
        String assignee = "张经理";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("myEvection")
                .taskAssignee(assignee)
                .list();
        for (Task task : tasks) {
            System.out.println("流程实例id：" + task.getProcessInstanceId());
            System.out.println("任务id：" + task.getId());
            System.out.println("任务负责人：" + task.getAssignee());
            System.out.println("任务名称：" + task.getName());
        }
    }

    public final String PROCESS_DEFINITION_KEY = "myEvection";

    /**
     * 流程任务处理
     */
    @Test
    public void completeTask() {
        String assignee = "张经理";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(PROCESS_DEFINITION_KEY)
                .taskAssignee(assignee)
                .singleResult();
        taskService.complete(task.getId());
        System.out.println(assignee + "的任务：" + task.getName() + "  => 已完成");
    }

    /**
     * 通过zip方式部署，可以部署多个流程定义
     */
    @Test
    public void deployByZip() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .deploy();
        System.out.println(deployment.getId());
    }

    /**
     * 查看流程定义信息
     */
    @Test
    public void queryDefinition() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //查询所有流程定义
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.processDefinitionKey("myEvection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition processDefinition : processDefinitions) {
            System.out.println("流程定义id=" + processDefinition.getId());
            System.out.println("流程定义name=" + processDefinition.getName());
            System.out.println("流程定义key=" + processDefinition.getKey());
            System.out.println("流程定义version=" + processDefinition.getVersion());
            System.out.println("流程部署ID=" + processDefinition.getDeploymentId());
        }
    }

    /**
     * 删除流程
     * 说明：
     * 1) 使用repositoryService删除流程定义，历史表（ACT_HI）信息不会被删除
     * 2)  如果该流程定义下没有正在运行的流程，则可以用普通删除。
         * 如果该流程定义下存在已经运行的流程，使用普通删除报错，可用 级联删除 方法 将流程及相关记录全部删除。
         * 先删除没有完成流程节点，最后就可以完全删除流程定义信息
         * 项目开发中级联删除操作一般只开放给 超级管理员 使用.
     */
    @Test
    public void deleteDeployment() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.processDefinitionKey(PROCESS_DEFINITION_KEY)
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition processDefinition : processDefinitions) {
            String deploymentId = processDefinition.getDeploymentId();
            //普通删除
            repositoryService.deleteDeployment(deploymentId);
            //如果流程顶定义下有正在运行的流程，则级联删除
            //repositoryService.deleteDeployment(deploymentId,true);
        }
    }

    /**
     * 流程资源下载（Bpmn和PNG）,核心就是通过RepositoryService来拿到资源流
     */
    @Test
    public void downloadProcessSource() throws IOException {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //获得流程定义对象
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey(PROCESS_DEFINITION_KEY)
                .orderByProcessDefinitionVersion()
                .desc()
                .singleResult();
        //部署ID
        String deploymentId = processDefinition.getDeploymentId();
        //从流程定义表中，获取png图片目录
        String diagramResourceName = processDefinition.getDiagramResourceName();
        //通过getResourceAsStream，传递 部署ID 和 资源名称 来拿到 资源
        InputStream diagramResourceAsStream = repositoryService.getResourceAsStream(deploymentId, diagramResourceName);
        //从流程定义表中，获取bpmn文件目录
        String resourceName = processDefinition.getResourceName();
        //通过getResourceAsStream，传递 部署ID 和 资源名称 来拿到 资源
        InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
        //够造输出流
        File file1 = new File("D:\\activitiSource\\evection.png");
        File file2 = new File("D:\\activitiSource\\evection.bpmn");
        FileOutputStream outputStream1 = new FileOutputStream(file1);
        FileOutputStream outputStream2 = new FileOutputStream(file2);
        //输入输出流转换
        IOUtils.copy(diagramResourceAsStream,outputStream1);
        IOUtils.copy(resourceAsStream,outputStream2);
        //关闭流资源
        outputStream2.close();
        outputStream1.close();
        resourceAsStream.close();
        diagramResourceAsStream.close();
    }

    /**
     * 查看历史任务
     */
    @Test
    public void findHistoryInfo() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        //对应act_hi_actinst
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //类似于Criteria查询拼接各种条件
        //根据流程实例ID查询
        historicActivityInstanceQuery.processInstanceId("12501");
        //根据流程定义ID查询
        //historicActivityInstanceQuery.processDefinitionId("myEvection:1:10004");
        List<HistoricActivityInstance> list = historicActivityInstanceQuery.orderByHistoricActivityInstanceStartTime()
                .asc()
                .list();
        for (HistoricActivityInstance historicActivityInstance : list) {
            if (historicActivityInstance.getActivityName().equals("开始")) continue;
            if (historicActivityInstance.getTaskId() != null) {
                System.out.println("任务ID："+historicActivityInstance.getTaskId());
            }
            System.out.println("任务名称："+historicActivityInstance.getActivityName());
            System.out.println("办理人："+historicActivityInstance.getAssignee());
            System.out.println("任务开始时间："+historicActivityInstance.getStartTime());
            if (historicActivityInstance.getEndTime() != null) {
                System.out.println("任务结束时间："+historicActivityInstance.getEndTime());
            }
            System.out.println();
        }
    }
}
